package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.mapper.CartInfoMapper;
import com.atguigu.gmall.cart.service.CartInfoService;
import com.atguigu.gmall.cart.service.CartInfoSyncService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.AuthContextHolder;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class CartInfoServiceImpl extends ServiceImpl<CartInfoMapper,CartInfo> implements CartInfoService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private CartInfoSyncService cartInfoSyncService;
    //加入商品到购物车
    //@Override
    public void addToCart(Long skuId, Integer skuNum,String userId) {
        System.out.println("主线程的名字:"+Thread.currentThread().getName());
        //1.(重要)保存购物车到redis缓存中
        // h  user:3:cart   真实用户的购物车
        // h  user:abgsrdffgrfsdgrfg:cart  临时用户的购物车
        String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        //1.1查询缓存中的购物车
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(cartHKey, skuId.toString());
        if (null != cartInfo){
            //则此用户在之前已经添加过此商品 本次追加数量
            cartInfo.setSkuNum(cartInfo.getSkuNum()+skuNum);
            //2(不重要).修改购物车DB中的数量
            cartInfoSyncService.updateCartInfo(cartInfo);
        }else {
            //此用户在之前没有添加过此商品  添加此商品
            cartInfo = new CartInfo();
            cartInfo.setUserId(userId);
            cartInfo.setSkuId(skuId);
            cartInfo.setSkuNum(skuNum);
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            BigDecimal price = productFeignClient.getPrice(skuId);
            cartInfo.setCartPrice(price);
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setSkuName(skuInfo.getSkuName());
            //（不重要） 2:保存购物车到DB中
            cartInfoSyncService.insertCartInfo(cartInfo);
        }
        //走了加入购物车之后必须选上
        cartInfo.setIsChecked(1);

        //保存回缓存   1写
        //Map h = new HashMap()  h.put(hk,hv)
        redisTemplate.opsForHash().put(cartHKey,skuId.toString(),cartInfo);
    }

    //查看购物车里面的内容
    @Override
    public CartInfo toCart(Long skuId) {
        String userId = null;
        //在springIOC容器, 任意位置都可以获取HttpServletRequest
        ServletRequestAttributes servletRequestAttributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (null != servletRequestAttributes) {
            HttpServletRequest request = servletRequestAttributes.getRequest();
            userId = AuthContextHolder.getUserId(request);
            if (StringUtils.isEmpty(userId)){
                userId = AuthContextHolder.getUserTempId(request);
            }
        }
        String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        //1.1查询缓存中的购物车
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(cartHKey, skuId.toString());
        return cartInfo;
    }

    //查询购物车集合
    @Override
    public List<CartInfo> cartList(String userId, String userTempId) {
        //分为临时用户id和真实用户id
        /*
        当真实用户id存在时则把临时用户地购物车整合到真实用户中 并且清除临时用户的信息
        当真实用户不存在时,则只查询临时用户地购物车
         */

        //1.判断用户是否登录(是否有真实的用户id)
        if (!StringUtils.isEmpty(userId)){
            //用户登录了 有真实的用户id
            //1.1判断是否有临时的用户id
            if (!StringUtils.isEmpty(userTempId)){
                //有临时的用户id,需要合并真实用户id 和临时用户id
                //大合并
                return mergeCartInfoList(userId,userTempId);
            }else {
                //没有临时的用户id,直接查询真实的用户id即可
                return getCartInfoList(userId);
            }
        }else {
            //用户没有登录 没有真实的用户id
            if (!StringUtils.isEmpty(userTempId)){
                //有临时用户
                return getCartInfoList(userTempId);
            }else {
                //没有临时用户id,直接返回null
                return null;
            }
        }
    }

    //选中或者取消选中
    @Override
    public void checkCart(Long skuId, Integer isChecked, HttpServletRequest request) {
        String userId = AuthContextHolder.getUserId(request);
        if (StringUtils.isEmpty(userId)){
            //用户id为空,需要使用临时用户id
            userId = AuthContextHolder.getUserTempId(request);
        }
        //1.缓存的选中与取消
        String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(cartHKey, skuId.toString());
        cartInfo.setIsChecked(isChecked);
        redisTemplate.opsForHash().put(cartHKey,skuId.toString(),cartInfo);
        //2.修改DB 后台管理员可见
        cartInfoSyncService.updateCartInfo(cartInfo);
    }

    //查询商品清单  查询购物车中已经选中的商品集合
    @Override
    public List<CartInfo> getCartInfoListByChecked(String userId) {
        String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cartHKey);
        //过滤 已经选中的要,选不中的不要 filter 返回值为true就是要 反之就是不要
        List<CartInfo> result = cartInfoList.stream().filter(cartInfo -> {
            return 1 == cartInfo.getIsChecked();
        }).peek(cartInfo -> {
            BigDecimal price = productFeignClient.getPrice(cartInfo.getSkuId());
            cartInfo.setSkuPrice(price);
        }).collect(Collectors.toList());
        return result;
    }


    //大合并: 根据真实的用户id和临时的用户id合并 返回一个带有真实用户id的所有的List<CartInfo>集合
    private List<CartInfo> mergeCartInfoList(String userId, String userTempId) {
        //1: 根据真实用户id获取集合
        List<CartInfo> cartInfoList = getCartInfoList(userId);
        //2:根据临时用户id获取集合
        List<CartInfo> cartInfoListTemp = getCartInfoList(userTempId);
        //3:开始合并
        if (!CollectionUtils.isEmpty(cartInfoList)){
            //真实用户的购物车集合是有的
            if (!CollectionUtils.isEmpty(cartInfoListTemp)){
                //有临时用户的购车车集合: 开始合并
                //真正的大合并
                List<CartInfo> result = dahebing(cartInfoList, cartInfoListTemp, userId, userTempId);
                return result;
            }else {
                //没有临时用户的购物车集合,直接返回真实用户的购物车集合
                return cartInfoList;
            }
        }else {
            //真实用户的购物车里面没有东西,返回临时用户的购物车集合
            return cartInfoListTemp;
        }
    }



    //真正的大合并
    private List<CartInfo> dahebing(List<CartInfo> cartInfoList, List<CartInfo> cartInfoListTemp,
                          String userId,String userTempId) {
        //才开始真正的大合并
        //Map K : skuId   V: CartInfo
        Map<String, CartInfo> cartInfoMap = cartInfoList.stream().collect(Collectors.toMap(
                cartInfo -> cartInfo.getSkuId().toString(),
                cartInfo -> cartInfo
        ));

        //遍历临时用户的购物车集合 和cartInfoMap(真实用户的购物车map)对比,
        // 如果skuId一样就是同一款商品
        for (CartInfo cartInfoTemp : cartInfoListTemp) {
            CartInfo cartInfo = cartInfoMap.get(cartInfoTemp.getSkuId().toString());
            if (null != cartInfo){
                //遇到相同商品增加数量
                cartInfo.setSkuNum(cartInfo.getSkuNum() + cartInfoTemp.getSkuNum());
                //设置商品选中
                cartInfo.setIsChecked(1);
            }else {
                //遇不到相同的商品增加新商品
                cartInfoTemp.setUserId(userId);
                cartInfoMap.put(cartInfoTemp.getSkuId().toString(),cartInfoTemp);
            }
        }
        //更新mysql和redis缓存
        //统一处理:删除此临时用户id和真实用户id
        cartInfoMapper.delete(new QueryWrapper<CartInfo>()
        .in("user_id",userId,userTempId));
        Collection<CartInfo> values = cartInfoMap.values();

        List<CartInfo> resultDB = new ArrayList<>(cartInfoMap.values());
        //统一将购物车的集合添加到DB中
        this.saveBatch(resultDB);

        //统一删除redis临时用户中的hash
        String cartHKeyTemp = RedisConst.USER_KEY_PREFIX + userTempId + RedisConst.USER_CART_KEY_SUFFIX;
        redisTemplate.delete(cartHKeyTemp);
        //统一添加购物车缓存
        String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        redisTemplate.opsForHash().putAll(cartHKey,cartInfoMap);
        return resultDB;
    }

    //根据用户的id,获取购物车集合
    public List<CartInfo> getCartInfoList(String userId){
        String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        //查询缓存中的购物车集合
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cartHKey);
        //查询实时价格并且把实时价格放到购物车集合中 并且根据skuPrice排序
        List<CartInfo> result = cartInfoList.stream().peek(cartInfo -> {
            BigDecimal price = productFeignClient.getPrice(cartInfo.getSkuId());
            cartInfo.setSkuPrice(price);
        }).sorted((cartInfo1, cartInfo2) -> {
            return cartInfo2.getSkuPrice().intValue() - cartInfo1.getSkuPrice().intValue();
        }).collect(Collectors.toList());
        //返回购物车集合
        return result;
    }

    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private CartInfoMapper cartInfoMapper;
}
